/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = ora_comm.h                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2014/10/09 by songbb                               */
/*******************************************************************/

#ifndef __ORA_COMM_H_
#define __ORA_COMM_H_

#include <sys/time.h>

#include "frlist.h"

#include "../ora_core.h"

#define APM_ORA_DBG 0                   // 是否启用Debug
#define APM_ORA_SUPPORT_OCI 1           // 是否支持OCI
#define APM_ORA_ENABLE_FRLOG 0          // 是否启用日志记录
#define APM_ORA_ENABLE_COLOR_PRINT 1    // 是否启用彩色打印

/* 最大一次分配内存大小 512KB */
#define APM_ORA_MEM_MAX_SIZE 524288

/* 通用头长度 */
#define APM_ORA_PKT_HEADER_LEN 8
/* Data Flag长度 */
#define APM_ORA_DATA_FLAG_LEN 2

/* number类型数据转字符串时最大的长度 */
#define APM_ORA_NUMBER_STR_MAXLEN 128

/* 检查batch count的阈值 */
#define APM_ORA_BATCH_COUNT_THRESHOLD 100000

#define APM_ORA_REPORT_SESSION_SID APM_REPORT_KEY_SESSION".sql.dbname"
#define APM_ORA_REPORT_SESSION_PROGRAM APM_REPORT_KEY_SESSION".sql.program_name"

#define APM_ORA_PHASE_P_CONNECT                 0x1           /* 0000 0000 0000 0001 */
#define APM_ORA_PHASE_P_RESEND                  0x2           /* 0000 0000 0000 0010 */
#define APM_ORA_PHASE_P_RECONNECT               0x4           /* 0000 0000 0000 0100 */
#define APM_ORA_PHASE_P_ACCEPT                  0x8           /* 0000 0000 0000 1000 */
#define APM_ORA_PHASE_P_PRO_REQ                 0x10          /* 0000 0000 0001 0000 */
#define APM_ORA_PHASE_P_PRO_RESP                0x20          /* 0000 0000 0010 0000 */
#define APM_ORA_PHASE_P_DTY_REQ                 0x40          /* 0000 0000 0100 0000 */
#define APM_ORA_PHASE_P_DTY_RESP                0x80          /* 0000 0000 1000 0000 */
#define APM_ORA_PHASE_P_LOG1_REQ                0x100         /* 0000 0001 0000 0000 */
#define APM_ORA_PHASE_P_LOG1_RESP               0x200         /* 0000 0010 0000 0000 */
#define APM_ORA_PHASE_P_LOG2_REQ                0x400         /* 0000 0100 0000 0000 */
#define APM_ORA_PHASE_P_LOG2_RESP               0x800         /* 0000 1000 0000 0000 */
#define APM_ORA_PHASE_P_OVERSION_REQ            0x1000        /* 0001 0000 0000 0000 */
#define APM_ORA_PHASE_P_OVERSION_RESP           0x2000        /* 0010 0000 0000 0000 */

#define APM_ORA_SET_PHASE_P_CONNECT(x)             (x=(x)|APM_ORA_PHASE_P_CONNECT)
#define APM_ORA_SET_PHASE_P_RESEND(x)              (x=(x)|APM_ORA_PHASE_P_RESEND)
#define APM_ORA_SET_PHASE_P_RECONNECT(x)           (x=(x)|APM_ORA_PHASE_P_RECONNECT)
#define APM_ORA_SET_PHASE_P_ACCEPT(x)              (x=(x)|APM_ORA_PHASE_P_ACCEPT)
#define APM_ORA_SET_PHASE_P_PRO_REQ(x)             (x=(x)|APM_ORA_PHASE_P_PRO_REQ)
#define APM_ORA_SET_PHASE_P_PRO_RESP(x)            (x=(x)|APM_ORA_PHASE_P_PRO_RESP)
#define APM_ORA_SET_PHASE_P_DTY_REQ(x)             (x=(x)|APM_ORA_PHASE_P_DTY_REQ)
#define APM_ORA_SET_PHASE_P_DTY_RESP(x)            (x=(x)|APM_ORA_PHASE_P_DTY_RESP)
#define APM_ORA_SET_PHASE_P_LOG1_REQ(x)            (x=(x)|APM_ORA_PHASE_P_LOG1_REQ)
#define APM_ORA_SET_PHASE_P_LOG1_RESP(x)           (x=(x)|APM_ORA_PHASE_P_LOG1_RESP)
#define APM_ORA_SET_PHASE_P_LOG2_REQ(x)            (x=(x)|APM_ORA_PHASE_P_LOG2_REQ)
#define APM_ORA_SET_PHASE_P_LOG2_RESP(x)           (x=(x)|APM_ORA_PHASE_P_LOG2_RESP)
#define APM_ORA_SET_PHASE_P_OVERSION_REQ(x)        (x=(x)|APM_ORA_PHASE_P_OVERSION_REQ)
#define APM_ORA_SET_PHASE_P_OVERSION_RESP(x)       (x=(x)|APM_ORA_PHASE_P_OVERSION_RESP)

#define APM_ORA_HAS_PHASE_P_CONNECT(x)             ((x)&APM_ORA_PHASE_P_CONNECT)
#define APM_ORA_HAS_PHASE_P_RESEND(x)              ((x)&APM_ORA_PHASE_P_RESEND)
#define APM_ORA_HAS_PHASE_P_RECONNECT(x)           ((x)&APM_ORA_PHASE_P_RECONNECT)
#define APM_ORA_HAS_PHASE_P_ACCEPT(x)              ((x)&APM_ORA_PHASE_P_ACCEPT)
#define APM_ORA_HAS_PHASE_P_PRO_REQ(x)             ((x)&APM_ORA_PHASE_P_PRO_REQ)
#define APM_ORA_HAS_PHASE_P_PRO_RESP(x)            ((x)&APM_ORA_PHASE_P_PRO_RESP)
#define APM_ORA_HAS_PHASE_P_DTY_REQ(x)             ((x)&APM_ORA_PHASE_P_DTY_REQ)
#define APM_ORA_HAS_PHASE_P_DTY_RESP(x)            ((x)&APM_ORA_PHASE_P_DTY_RESP)
#define APM_ORA_HAS_PHASE_P_LOG1_REQ(x)            ((x)&APM_ORA_PHASE_P_LOG1_REQ)
#define APM_ORA_HAS_PHASE_P_LOG1_RESP(x)           ((x)&APM_ORA_PHASE_P_LOG1_RESP)
#define APM_ORA_HAS_PHASE_P_LOG2_REQ(x)            ((x)&APM_ORA_PHASE_P_LOG2_REQ)
#define APM_ORA_HAS_PHASE_P_LOG2_RESP(x)           ((x)&APM_ORA_PHASE_P_LOG2_RESP)
#define APM_ORA_HAS_PHASE_P_OVERSION_REQ(x)        ((x)&APM_ORA_PHASE_P_OVERSION_REQ)
#define APM_ORA_HAS_PHASE_P_OVERSION_RESP(x)       ((x)&APM_ORA_PHASE_P_OVERSION_RESP)


#if APM_ORA_ENABLE_COLOR_PRINT
    #define KRED        "\x1B[0;31m"
    #define KRED_BACK   "\x1B[7;31m"
    #define KSALMON     "\x1B[1;31m"
    #define KGREEN      "\x1B[0;32m"
    #define KLIMEGREEN  "\x1B[1;32m"
    #define KYELLOW     "\x1B[0;33m"
    #define KORANGE     "\x1B[0;34m"
    #define KBLUE       "\x1B[1;34m"
    #define KMAGENTA    "\x1B[0;35m"
    #define KPINK       "\x1B[1;35m"
    #define KCYAN       "\x1B[0;36m"
    #define RESET       "\x1B[0m"
#else
    #define KRED        ""
    #define KRED_BACK   ""
    #define KSALMON     ""
    #define KGREEN      ""
    #define KLIMEGREEN  ""
    #define KYELLOW     ""
    #define KORANGE     ""
    #define KBLUE       ""
    #define KMAGENTA    ""
    #define KPINK       ""
    #define KCYAN       ""
    #define RESET       ""
#endif


#if APM_ORA_DBG
    #define ORA_PRINT(...) printf(__VA_ARGS__)
    #define ORA_PRINT_DETAIL(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(__VA_ARGS__))
    #define ORA_PRINT_DBG(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KGREEN),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_FATAL(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KORANGE),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_EMERG(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KRED),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_ALERT(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KSALMON),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_CRIT(...) (printf("[%s, Line:%u, %s()]",\
                            __FILE__,__LINE__,__func__),\
                            printf(KMAGENTA),\
                            printf(" "__VA_ARGS__),\
                            printf(RESET))
    #define ORA_PRINT_ERR(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KPINK),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_WARN(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KYELLOW),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_NOTICE(...) (printf("[%s, Line:%u, %s()]",\
                        __FILE__,__LINE__,__func__),\
                        printf(KLIMEGREEN),\
                        printf(" "__VA_ARGS__),\
                        printf(RESET))
    #define ORA_PRINT_INFO(...) (printf("[%s, Line:%u, %s()]",\
                            __FILE__,__LINE__,__func__),\
                            printf(KBLUE),\
                            printf(" "__VA_ARGS__),\
                            printf(RESET))
    #define ORA_PRINT_PARAM(...) (printf("[%s, Line:%u, %s()]",\
                            __FILE__,__LINE__,__func__),\
                            printf(KRED_BACK),\
                            printf(" "__VA_ARGS__),\
                            printf(RESET))
#else
    #define ORA_PRINT(...)
    #define ORA_PRINT_DETAIL(...)
    #define ORA_PRINT_DBG(...)
    #define ORA_PRINT_FATAL(...)
    #define ORA_PRINT_EMERG(...)
    #define ORA_PRINT_ALERT(...)
    #define ORA_PRINT_CRIT(...)
    #define ORA_PRINT_ERR(...)
    #define ORA_PRINT_WARN(...)
    #define ORA_PRINT_NOTICE(...)
    #define ORA_PRINT_INFO(...)
    #define ORA_PRINT_PARAM(...)
#endif

#if APM_ORA_ENABLE_FRLOG
    #define ORA_FRLOG_ERROR(...) FRLOG_ERROR_DETAIL(...)
#else
    #define ORA_FRLOG_ERROR(...)
#endif

#define ora_malloc(size, limit) __ora_malloc(size, limit)

#define ORA_MALLOCK_ERR ORA_PRINT_EMERG("can not malloc memory\n"); \
                          FRLOG_ERROR_DETAIL("can not malloc memory");

/*
 * 解析(DESCRIPTION=(CONNECT_DATA=(SID=orcl)(CID=(PROGRAM=)(HOST=__jdbc__)(USER=win)))(ADDRESS=(PROTOCOL=tcp)(HOST=172.16.0.74)(PORT=1521)))
 */
typedef struct __st_ora_NVPair
{
    char *key;                     // 键字符串 例如：DESCRIPTION.CONNECT_DATA.SID
    char *value;                   // 值       例如：orcl
} Ora_NVPair;

void* __ora_malloc(size_t s_size
                , int i_limit);

void ora_free(void **pp_buffer);

int ora_NVPair_parser(char *p_data
                    , unsigned int ui_len
                    , Frlist_header *p_st_head
                    , Frstr *p_ancestor_keys);

int ora_NVPair_get_value(Frlist_header *p_st_head
                        , const char *p_keys
                        , char **pp_value);

void ora_NVPair_list_node_free(Frlist_node *node);

void ora_set_ttc_type_rep(L7session_ora *p_st_sess
                        , int i_location
                        , int i_value);

int ora_get_ttc_type_rep(L7session_ora *p_st_sess
                        , int i_location);

void ora_unset_ttc_type_rep(L7session_ora *p_st_sess);

void ora_set_ttc_type_rep_jdbc(L7session_ora *p_st_sess);

void ora_push_sess_phase(Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]
                        , Ora_sess_phase em_sess_phase);

Ora_sess_phase ora_pop_sess_phase(Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]);

void ora_set_last_sess_phase(Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]
                        , Ora_sess_phase em_sess_phase);

int ora_is_sess_phase_null(Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]);

void ora_reset_sess_phase(Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]);

void ora_add_sess_phase(Ora_sess_phase arr_src_sess_phase[APM_ORA_SESS_PHASE_MAX]
                        , Ora_sess_phase arr_dest_sess_phase[APM_ORA_SESS_PHASE_MAX]);

void ora_copy_sess_phase(Ora_sess_phase arr_src_sess_phase[APM_ORA_SESS_PHASE_MAX]
                        , Ora_sess_phase arr_dest_sess_phase[APM_ORA_SESS_PHASE_MAX]);

void ora_remaining_last_sess_phase(Ora_sess_phase arr_sess_phase[APM_ORA_SESS_PHASE_MAX]);

int ora_has_svr_compile_time_capability(L7session_ora *p_st_sess
                                        , int i_len
                                        , int i_value);

void ora_reset_resp_info(L7_resp_ora *p_st_resp);

void ora_sess_set_large_sdu_flag(L7session_ora *p_st_sess
                                , int i_large_sdu_flag);

int ora_report_stmt_req(Conntrack *p_st_conn
                        , L7session_ora *p_st_sess
                        , Sql_statement *p_st_stmt
                        , Frhash_header *p_st_hash_report);

int ora_report_stmt_resp(Conntrack *p_st_conn
                        , L7session_ora *p_st_sess
                        , Sql_statement *p_st_stmt
                        , Frhash_header *p_st_hash_report
                        , int i_last_resultset);

void ora_packet_need_next_packet(L7_ora_packet *p_st_ora_packet);

int ora_packet_is_in_fragment(L7_ora_packet *p_st_ora_packet);

int ora_is_sql(char *p_sql
            , int i_sql_len);

int ora_is_sql_select(char *p_sql
                    , int i_sql_len);

int ora_is_sql_dml(char *p_sql
                , int i_sql_len);

void ora_service_list_add(L7session_ora *p_st_sess
                         , Apm_packet *p_st_packet);

void ora_frdata_free(Frdata_field **pp_st_field);

void ora_sql_delete_comments(char **p_sql);

#endif
